package com.finance.report.controller;

import com.finance.base.constant.BaseConstants;
import com.finance.base.enums.*;
import com.finance.base.exception.BaseException;
import com.finance.framework.controller.BaseController;
import com.finance.framework.controller.Result;
import com.finance.framework.file.FileUtils;
import com.finance.report.request.CalculateReq;
import com.finance.report.service.*;
import com.finance.rule.service.ISettingLogService;
import com.finance.system.bean.pojo.RecomputeTask;
import com.finance.system.bean.pojo.User;
import com.finance.system.response.ResetPullData;
import com.finance.system.service.IConfigService;
import com.finance.system.service.IRecomputeTaskService;
import com.finance.util.DateUtil;
import com.finance.util.OKHTTPUtil;
import com.finance.util.encrypt.EncryptUtil;
import com.finance.util.xml.JaxbUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.CountDownLatch;


/**
 * @Description 按月份清除统计并重新计算
 * @Author: lijinguo
 */
@Controller
@RequestMapping("/report/restatistics")
public class RestatisticsController extends BaseController {

    @Resource
    private ILogisticsDataService logisticsDataService;

    @Resource
    private ITimerManSalaryService timerManSalaryService;

    @Resource
    private ISettingLogService settingLogService;

    @Resource
    private IConfigService configService;

    @Resource
    private IOrganizationSalaryService organizationSalaryService;

    @Resource
    private ISupplierSalaryService supplierSalaryService;

    @Resource
    private ILogisticsExtendService logisticsExtendService;

    @Autowired
    private TaskExecutor taskExecutor;

    @Autowired
    private IRecomputeTaskService recomputeTaskService;

    @RequestMapping("/index.htm")
    public String index() {
        return "report/restatistics/index";
    }

    /**
     * @param date yyyy-MM 操作的月份
     * @Description 按月份清除统计并重新计算
     */
    @RequestMapping("/clearandcalculate")
    public Result clearAndCalculate(String date, HttpServletRequest request) {
        User user = getAuthUser();
        if (StringUtils.isEmpty(date)) {
            throw new BaseException(BaseConstants.ERR_PARAM_MISS);
        }
        String month = "";
        Date startDate = null;
        try {
            //1.删除拉取的运单数据、运单错误日志、运单拓展数据
            startDate = DateUtil.str2date(date, DateUtil.YEAR_AND_MONTH_FORMAT);
            month = DateUtil.dateFormat(startDate, DateUtil.YEAR_AND_MONTH_FORMAT);
        } catch (ParseException e) {
            throw new BaseException(BaseConstants.ERR_INVALID_PARAMETER);
        }
        //删除上传文件
        try {
            String suffix = "";
            if (StringUtils.isNotBlank(month)) {
                suffix = month.trim().replace("-", "").substring(2, 6);
            } else {
                throw new BaseException(BaseConstants.ERR_INVALID_PARAMETER);
            }
            String extendTableName = BaseConstants.SYSCONFIG_KEY_LOGISTICS_EXTEND_TABLE + suffix;
            List<String> postmanNos = logisticsExtendService.getPostmans(extendTableName);
            String tableName = BaseConstants.SYSCONFIG_KEY_LOGISTICDATA_TABLE + suffix;
            Iterator<String> iterator = postmanNos.iterator();
            String postmanNo = "";
            while (iterator.hasNext()) {
                postmanNo = iterator.next();
                FileUtils.delFile(BaseConstants.FINANCE_REPORT_FILE_PATH + "/" + month + "-" + postmanNo + BaseConstants.DEFAULT_EXPORT_FILE_SUFFIX);
            }
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
        }
        this.logger.info("*************重算清除三表开始****************");
        logisticsDataService.deleteByMonthDate(startDate);
        this.logger.info("*************重算清除三表结束****************");
        //1. 删除供应商、机构月报表
        organizationSalaryService.deleteByMonth(month);
        supplierSalaryService.deleteByMonth(month);
        //2.删除配费计算的结果
        timerManSalaryService.del(month);
        boolean result = this.multiThreadHandle(startDate);
        if (result) {
            RecomputeTask recomputeTask = new RecomputeTask();
            recomputeTask.setMonth(month);
            recomputeTask.setPullStatus(PullStatusEnum.UNDO.getState());
            recomputeTask.setComputeStatus(ComputeStatusEnum.UNDO.getState());
            recomputeTask.setVersion(0);
            recomputeTask.setState(StateEnum.Valid.getState());
            if (null != this.recomputeTaskService.getByMonth(month)) {
                this.recomputeTaskService.delByMonth(month);
            }
            this.recomputeTaskService.addRecomputeTask(recomputeTask, user);
            return this.getSuccessResult(true);
        }
        settingLogService.addLog(user, OpearteEnum.RESTATISTICS, TargetEnum.MAN_SALARY, null);
        return getFailResult(BaseConstants.ERR_UNKOWN, "重算失败");
    }

    /**
     * 线程重置
     *
     * @param month
     * @return
     */
    private boolean multiThreadHandle(Date month) {
        List<String> list = DateUtil.genDays(month);
        final CountDownLatch countDownLatch = new CountDownLatch(list.size());
        for (int i = 0; i < list.size(); i++) {
            final String day = list.get(i);
            this.taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    boolean result = false;
                    //失败则尝试3次 calculateByDay仅调用一次
                    if (!result && (result = calculateByDay(day))) {
                        countDownLatch.countDown();
                    }
                    if (!result && (result = calculateByDay(day))) {
                        countDownLatch.countDown();
                    }
                    if (!result && (result = calculateByDay(day))) {
                        countDownLatch.countDown();
                    }
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        }
        return true;
    }

    /**
     * 重置拉单
     * yyyyMMdd
     *
     * @param day
     */
    private boolean calculateByDay(String day) {
        /**运单拉取重置开始**/
        String calculateUrl = this.configService.findConfig(BaseConstants.SYSCONFIG_KEY_CHUYAN_OMS_CALCULATE);//运单拉取重置回调地址
        CalculateReq calculateRequest = calculateRequestOfDay(day);
        Map<String, String> param = new HashMap<String, String>();
        param.put("param", JaxbUtil.bean2xml(calculateRequest));
        String responseStr = "";
        try {
            responseStr = OKHTTPUtil.postForm(calculateUrl.trim(), param);
        } catch (Exception e) {
            logger.info("***************重置拉单接口返回******************************" + responseStr);
            logger.error(e.getMessage(), e);
            return false;
        }
        ResetPullData resetPullData = JaxbUtil.converyToJavaBean(responseStr, ResetPullData.class);
        String errorCode = resetPullData.getErrorCode();
        return "00".equals(errorCode);
    }

    /**
     * 创建重置请求参数
     * yyyyMMdd
     *
     * @param day
     * @return
     */
    private CalculateReq calculateRequestOfDay(String day) {
        CalculateReq calculateRequest = new CalculateReq();
        Date calculateDate = null;
        try {
            calculateDate = DateUtil.str2date(day, DateUtil.SIMPLE_FORMAT);
        } catch (ParseException e) {
            logger.error(e.getMessage(), e);
            this.logger.info("日期格式化异常：" + e.getMessage());
        }
        /**
         * 往请求bean中填充值
         */
        Calendar from = Calendar.getInstance();//前移动一天 第一秒
        from.setTime(calculateDate);
        from.set(Calendar.HOUR_OF_DAY, 0);
        from.set(Calendar.MINUTE, 0);
        from.set(Calendar.SECOND, 0);
        Calendar to = Calendar.getInstance();//前移动一天 最后一秒
        to.setTime(calculateDate);
        to.set(Calendar.HOUR_OF_DAY, 23);
        to.set(Calendar.MINUTE, 59);
        to.set(Calendar.SECOND, 59);
        /**
         * MD5小32位加密获取摘要后再base64加密
         */
        String requestTime = DateUtil.dateFormat(new Date(), DateUtil.SIMPLE_SECOND_FORMAT);
        String digestKey = this.configService.findConfig(BaseConstants.SYSCONFIG_KEY_CHUYAN_OMS_DIGISTKEY);//秘钥
        String str = requestTime + digestKey;
        String charset = this.configService.findConfig(BaseConstants.SYSCONFIG_KEY_CHUYAN_OMS_CHARSET);//字符编码格式
        calculateRequest.setRequestTime(requestTime);
        calculateRequest.setBeginTime(DateUtil.dateFormat(new Date(from.getTimeInMillis())));
        calculateRequest.setEndTime(DateUtil.dateFormat(new Date(to.getTimeInMillis())));
        calculateRequest.setDigest(EncryptUtil.md5Base64(str, charset));
        return calculateRequest;
    }
}
